﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CEIT.Domain;
using System.Web.Security;
using System.Web;
using CEIT.Infrastructure.Queries.Usuario;
using SharpArch.NHibernate;

namespace CEIT.Infrastructure.Queries.Authentication
{
    public class FormsAuthenticationService : NHibernateQuery<Domain.Usuario>, IAuthenticationService
    {

        private readonly HttpContextBase _httpContext;
        private readonly HttpSessionStateBase _httpContextSession;
        private readonly TimeSpan _expirationTimeSpan;
        private readonly IUsuarioQuery _UserAccountRepository;
        private Domain.Usuario _cachedUserAccount;

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="_UserAccountRepository">UserAccount service</param>
        public FormsAuthenticationService(HttpContextBase httpContext, IUsuarioQuery UserAccountRepository, HttpSessionStateBase httpContextSession)
        {
            this._httpContext = httpContext;
            this._expirationTimeSpan = FormsAuthentication.Timeout;
            this._UserAccountRepository = UserAccountRepository;
            this._httpContextSession = httpContextSession;
        }


        public override IList<Domain.Usuario> ExecuteQuery()
        {
            throw new NotImplementedException();
        }

        public virtual void SignIn(Domain.Usuario Usuario, bool createPersistentCookie)
        {
            var now = DateTime.UtcNow.ToLocalTime();

            var ticket = new FormsAuthenticationTicket(
                1 /*version*/,
                Usuario.NmLogin,
                now,
                now.Add(_expirationTimeSpan),
                createPersistentCookie,
                Usuario.NmLogin,
                FormsAuthentication.FormsCookiePath);

#if DEBUG
            FormsAuthentication.SetAuthCookie(Usuario.NmLogin, createPersistentCookie);
#else
            var encryptedTicket = FormsAuthentication.Encrypt(ticket);

            var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
            cookie.HttpOnly = true;
            cookie.Expires = now.Add(_expirationTimeSpan);
            cookie.Secure = FormsAuthentication.RequireSSL;
            cookie.Path = FormsAuthentication.FormsCookiePath;
            if (FormsAuthentication.CookieDomain != null) {
                cookie.Domain = FormsAuthentication.CookieDomain;
            }
            _httpContext.Response.Cookies.Add(cookie);
#endif

            _cachedUserAccount = Usuario;
        }

        public virtual void SignOut()
        {
            var user = GetUserAuthenticated();
            if (user != null)
            {
                LogAcesso log = Session.QueryOver<LogAcesso>().Where(x => x.Usuario == user && x.DtLogout == null)
                                    .OrderBy(x => x.Id).Desc
                                    .List()
                                    .FirstOrDefault();
                if (log != null)
                {
                    log.DtLogout = DateTime.Now;
                    Session.Transaction.Begin();
                    Session.Save(log);
                    Session.Transaction.Commit();
                    Session.Transaction.Dispose();

                }
            }
            _cachedUserAccount = null;
            FormsAuthentication.SignOut();
            HttpContext.Current.Session.Abandon();
        }

        public virtual Domain.Usuario GetUserAuthenticated()
        {
            if (_cachedUserAccount != null)
                return _cachedUserAccount;

            if (_httpContext == null || _httpContext.Request == null || !_httpContext.Request.IsAuthenticated || !(_httpContext.User.Identity is FormsIdentity))
                return null;

            var formsIdentity = (FormsIdentity)_httpContext.User.Identity;
            var UserAccount = GetUserAuthenticatedFromTicket(formsIdentity.Ticket);
            if (UserAccount != null)
                _cachedUserAccount = UserAccount;
            return _cachedUserAccount;
        }

        public virtual Domain.Usuario GetUserAuthenticatedFromTicket(FormsAuthenticationTicket ticket)
        {
            if (ticket == null)
                throw new ArgumentNullException("ticket");

            var Login = ticket.Name;

            if (String.IsNullOrWhiteSpace(Login))
                return null;
            var UserAccount = _UserAccountRepository.GetByUserName(Login);
            return UserAccount;
        }

    }
}
